home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / gdb / foo / readline / vi_mode.c < prev   
Encoding:
C/C++ Source or Header  |  1989-10-19  |  14.3 KB  |  857 lines

  1. /* vi_mode.c -- A vi emulation mode for Bash.
  2.    Mostly written by Jeff Sparkes (jeff1@????).
  3.  */
  4.  
  5.  
  6. /* **************************************************************** */
  7. /*                                    */
  8. /*            VI Emulation Mode                */
  9. /*                                    */
  10. /* **************************************************************** */
  11.  
  12. /* Last string searched for from `/' or `?'. */
  13. static char *vi_last_search = (char *)NULL;
  14. static int vi_histpos;
  15.  
  16. /* *** UNCLEAN *** */
  17. /* Command keys which do movement for xxx_to commands. */
  18. static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
  19.  
  20. /* Keymap used for vi replace characters.  Created dynamically since
  21.    rarely used. */
  22. static Keymap vi_replace_map = (Keymap)NULL;
  23.  
  24. /* The number of characters inserted in the last replace operation. */
  25. static vi_replace_count = 0;
  26.  
  27. /* Yank the nth arg from the previous line into this line at point. */
  28. rl_vi_yank_arg (count)
  29.      int count;
  30. {
  31.   rl_yank_nth_arg (count);
  32. }
  33.  
  34. /* Search again for the last thing searched for. */
  35. rl_vi_search_again (ignore, key)
  36.      int ignore, key;
  37. {
  38.   switch (key)
  39.     {
  40.     case 'n':
  41.       rl_vi_dosearch (vi_last_search, -1);
  42.       break;
  43.  
  44.     case 'N':
  45.       rl_vi_dosearch (vi_last_search, 1);
  46.       break;
  47.     }
  48. }
  49.  
  50. /* Do a vi style search. */
  51. rl_vi_search (count, key)
  52.      int count, key;
  53. {
  54.   int dir, c;
  55.   char *p;
  56.  
  57.   switch (key)
  58.     {
  59.     case '?':
  60.       dir = 1;
  61.       break;
  62.  
  63.     case '/':
  64.       dir = -1;
  65.       break;
  66.  
  67.     default:
  68.       ding ();
  69.       return;
  70.     }
  71.  
  72.   vi_histpos = where_history ();
  73.   maybe_save_line ();
  74.  
  75.   /* Reuse the line input buffer to read the search string. */
  76.   the_line[0] = 0;
  77.   rl_end = rl_point = 0;
  78.   p = (char *)alloca (2 + rl_prompt ? strlen (rl_prompt) : 0);
  79.  
  80.   sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
  81.  
  82.   rl_message (p);
  83.  
  84.   while (c = rl_read_key (in_stream))
  85.     {
  86.       switch (c)
  87.     {
  88.     case CTRL('W'):
  89.     case CTRL('U'):
  90.     case CTRL('H'):
  91.     case RUBOUT:
  92.       rl_dispatch (c, keymap);
  93.       break;
  94.  
  95.     case ESC:
  96.     case RETURN:
  97.     case NEWLINE:
  98.       goto dosearch;
  99.       break;
  100.  
  101.     case CTRL('C'):
  102.       maybe_unsave_line ();
  103.       rl_clear_message ();
  104.       rl_point = 0;
  105.       ding ();
  106.       return;
  107.  
  108.     default:
  109.       rl_insert (1, c);
  110.       break;
  111.     }
  112.       rl_redisplay ();
  113.     }
  114.  dosearch:
  115.   if (vi_last_search)
  116.     free (vi_last_search);
  117.  
  118.   vi_last_search = savestring (the_line);
  119.   rl_vi_dosearch (the_line, dir);
  120. }
  121.  
  122. rl_vi_dosearch (string, dir)
  123.      char *string;
  124.      int dir;
  125. {
  126.   int old, save = vi_histpos;
  127.   HIST_ENTRY *h;
  128.  
  129.   if (string == 0 || *string == 0 || vi_histpos < 0)
  130.     {
  131.       ding ();
  132.       return;
  133.     }
  134.  
  135.   if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1)
  136.     {
  137.       maybe_unsave_line ();
  138.       rl_clear_message ();
  139.       rl_point = 0;
  140.       ding ();
  141.       return;
  142.     }
  143.  
  144.   vi_histpos = save;
  145.  
  146.   old = where_history ();
  147.   history_set_pos (vi_histpos);
  148.   h = current_history ();
  149.   history_set_pos (old);
  150.  
  151.   strcpy (the_line, h->line);
  152.   rl_undo_list = (UNDO_LIST *)h->data;
  153.   rl_end = strlen (the_line);
  154.   rl_point = 0;
  155.   rl_clear_message ();
  156. }
  157.  
  158. /* Completion, from vi's point of view. */
  159. rl_vi_complete (ignore, key)
  160.      int ignore, key;
  161. {
  162.   if (!whitespace (the_line[rl_point]))
  163.     {
  164.       rl_vi_end_word (1, 'E');
  165.       rl_point++;
  166.     }
  167.   rl_complete_internal ('*');
  168.   rl_vi_insertion_mode ();
  169. }
  170.  
  171. /* Previous word in vi mode. */
  172. rl_vi_prev_word (count, key)
  173.      int count, key;
  174. {
  175.   if (count < 0)
  176.     {
  177.       rl_vi_next_word (-count, key);
  178.       return;
  179.     }
  180.  
  181.   if (uppercase_p (key))
  182.     rl_vi_bWord (count);
  183.   else
  184.     rl_vi_bword (count);
  185. }
  186.  
  187. /* Next word in vi mode. */
  188. rl_vi_next_word (count, key)
  189.      int count;
  190. {
  191.   if (count < 0)
  192.     {
  193.       rl_vi_prev_word (-count, key);
  194.       return;
  195.     }
  196.  
  197.   if (uppercase_p (key))
  198.     rl_vi_fWord (count);
  199.   else
  200.     rl_vi_fword (count);
  201. }
  202.  
  203. /* Move to the end of the ?next? word. */
  204. rl_vi_end_word (count, key)
  205.      int count, key;
  206. {
  207.   if (count < 0)
  208.     {
  209.       ding ();
  210.       return;
  211.     }
  212.  
  213.   if (uppercase_p (key))
  214.     rl_vi_eWord (count);
  215.   else
  216.     rl_vi_eword (count);
  217. }
  218.  
  219. /* Move forward a word the way that 'W' does. */
  220. rl_vi_fWord (count)
  221.      int count;
  222. {
  223.   while (count-- && rl_point < (rl_end - 1))
  224.     {
  225.       /* Skip until whitespace. */
  226.       while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
  227.     rl_point++;
  228.  
  229.       /* Now skip whitespace. */
  230.       while (whitespace (the_line[rl_point]) && rl_point < rl_end)
  231.     rl_point++;
  232.     }
  233. }
  234.  
  235. rl_vi_bWord (count)
  236.      int count;
  237. {
  238.   while (count-- && rl_point > 0)
  239.     {
  240.       while (rl_point-- >= 0 && whitespace (the_line[rl_point]));
  241.       while (rl_point >= 0 && !whitespace (the_line[rl_point]))
  242.     rl_point--;
  243.       rl_point++;
  244.     }
  245. }
  246.  
  247. rl_vi_eWord (count)
  248.      int count;
  249. {
  250.   while (count -- && rl_point < (rl_end - 1))
  251.     {
  252.       while (rl_point++ < rl_end && whitespace (the_line[rl_point]));
  253.       while (rl_point++ < rl_end && !whitespace (the_line[rl_point]));
  254.       rl_point--;
  255.     }
  256. }
  257.  
  258. rl_vi_fword (count)
  259.      int count;
  260. {
  261.   while (count -- && rl_point < (rl_end - 1))
  262.     {
  263.       if (isident (the_line[rl_point]))
  264.     {
  265.       while (isident (the_line[rl_point]) && rl_point < rl_end)
  266.         rl_point += 1;
  267.     }
  268.       else if (!whitespace (the_line[rl_point]))
  269.     {
  270.       while (!isident (the_line[rl_point]) &&
  271.          !whitespace (the_line[rl_point]) && rl_point < rl_end)
  272.         rl_point += 1;
  273.     }
  274.  
  275.       while (whitespace (the_line[rl_point]) && rl_point < rl_end)
  276.     rl_point++;
  277.     }
  278. }
  279.  
  280. rl_vi_bword (count)
  281.      int count;
  282. {
  283.   while (count -- && rl_point > 0)
  284.     {
  285.       while (--rl_point > 0 && whitespace (the_line[rl_point]));
  286.       if (rl_point > 0)
  287.     {
  288.       if (isident (the_line[rl_point]))
  289.         while (--rl_point >= 0 && isident (the_line[rl_point]));
  290.       else
  291.         while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
  292.            !whitespace (the_line[rl_point]));
  293.       rl_point++;
  294.     }
  295.     }
  296. }
  297.  
  298. rl_vi_eword (count)
  299.      int count;
  300. {
  301.   while (count -- && rl_point < rl_end - 1)
  302.     {
  303.       while (++rl_point < rl_end && whitespace (the_line[rl_point]));
  304.  
  305.       if (rl_point < rl_end)
  306.     {
  307.       if (isident (the_line[rl_point]))
  308.         while (++rl_point < rl_end && isident (the_line[rl_point]));
  309.       else
  310.         while (++rl_point < rl_end && !isident (the_line[rl_point])
  311.            && !whitespace (the_line[rl_point]));
  312.       rl_point--;
  313.     }
  314.     }
  315. }
  316.  
  317. rl_vi_insert_beg ()
  318. {
  319.   rl_beg_of_line ();
  320.   rl_vi_insertion_mode ();
  321.   return 0;
  322. }
  323.  
  324. rl_vi_append_mode ()
  325. {
  326.   if (rl_point < rl_end)
  327.     rl_point += 1;
  328.   rl_vi_insertion_mode ();
  329.   return 0;
  330. }
  331.  
  332. rl_vi_append_eol ()
  333. {
  334.   rl_end_of_line ();
  335.   rl_vi_append_mode ();
  336.   return 0;
  337. }
  338.  
  339. /* What to do in the case of C-d. */
  340. rl_vi_eof_maybe (count, c)
  341.      int count, c;
  342. {
  343.   rl_newline (1, '\n');
  344. }
  345.  
  346. /* Insertion mode stuff. */
  347.  
  348. /* Switching from one mode to the other really just involves
  349.    switching keymaps. */
  350. rl_vi_insertion_mode ()
  351. {
  352.   keymap = vi_insertion_keymap;
  353. }
  354.  
  355. rl_vi_movement_mode ()
  356. {
  357.   if (rl_point > 0)
  358.     rl_backward (1);
  359.  
  360.   keymap = vi_movement_keymap;
  361.   if (vi_doing_insert)
  362.     {
  363.       rl_end_undo_group ();
  364.       vi_doing_insert = 0;
  365.     }
  366. }
  367.  
  368. rl_vi_arg_digit (count, c)
  369.      int count, c;
  370. {
  371.   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
  372.     rl_beg_of_line ();
  373.   else
  374.     rl_digit_argument (count, c);
  375. }
  376.  
  377. /* Doesn't take an arg count in vi */
  378. rl_vi_change_case (ignore1, ignore2)
  379.      int ignore1, ignore2;
  380. {
  381.   char c = 0;
  382.  
  383.   if (uppercase_p (the_line[rl_point]))
  384.     c = to_lower (the_line[rl_point]);
  385.   else if (lowercase_p (the_line[rl_point]))
  386.     c = to_upper (the_line[rl_point]);
  387.  
  388.   /* Vi is kind of strange here. */
  389.   if (c)
  390.     {
  391.       rl_begin_undo_group ();
  392.       rl_delete (1);
  393.       rl_insert (1, c);
  394.       rl_end_undo_group ();
  395.       rl_vi_check ();
  396.     }
  397.   else
  398.     rl_forward (1);
  399. }
  400.  
  401. rl_vi_put (count, key)
  402.      int count, key;
  403. {
  404.   if (!uppercase_p (key))
  405.     rl_forward (1);
  406.  
  407.   rl_yank ();
  408.   rl_backward (1);
  409. }
  410.  
  411. rl_vi_check ()
  412. {
  413.   if (rl_point && rl_point == rl_end)
  414.     rl_point--;
  415. }
  416.  
  417. rl_vi_column (count)
  418. {
  419.   if (count > rl_end)
  420.     rl_end_of_line ();
  421.   else
  422.     rl_point = count - 1;
  423. }
  424.  
  425. int
  426. rl_vi_domove ()
  427. {
  428.   int c, save;
  429.  
  430.   rl_mark = rl_point;
  431.   c = rl_read_key (in_stream);
  432.  
  433.   if (!member (c, vi_motion))
  434.     {
  435.       if (digit (c))
  436.     {
  437.       save = rl_numeric_arg;
  438.       rl_digit_loop1 ();
  439.       rl_numeric_arg *= save;
  440.     }
  441.       else
  442.     return (-1);
  443.     }
  444.  
  445.   rl_dispatch (c, keymap);
  446.  
  447.   /* No change in position means the command failed. */
  448.   if (rl_mark == rl_point)
  449.     return (-1);
  450.  
  451.   if ((c == 'w' || c == 'W') && rl_point < rl_end)
  452.     rl_point--;
  453.  
  454.   if (rl_mark < rl_point)
  455.     exchange (rl_point, rl_mark);
  456.  
  457.   return (0);
  458. }
  459.  
  460. /* A simplified loop for vi. Don't dispatch key at end.
  461.    Don't recognize minus sign? */
  462. rl_digit_loop1 ()
  463. {
  464.   int key, c;
  465.  
  466.   while (1)
  467.     {
  468.       rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg);
  469.       key = c = rl_read_key ();
  470.  
  471.       if (keymap[c].type == ISFUNC &&
  472.       keymap[c].function == rl_universal_argument)
  473.     {
  474.       rl_numeric_arg *= 4;
  475.       continue;
  476.     }
  477.       c = UNMETA (c);
  478.       if (numeric (c))
  479.     {
  480.       if (rl_explicit_arg)
  481.         rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
  482.       else
  483.         rl_numeric_arg = (c - '0');
  484.       rl_explicit_arg = 1;
  485.     }
  486.       else
  487.     {
  488.       rl_clear_message ();
  489.       rl_stuff_char (key);
  490.     }
  491.     }
  492. }
  493.  
  494. rl_vi_delete_to (count, key)
  495.      int count, key;
  496. {
  497.   if (uppercase_p (key))
  498.     rl_stuff_char ('$');
  499.  
  500.   if (rl_vi_domove ())
  501.     {
  502.       ding ();
  503.       return;
  504.     }
  505.  
  506.   rl_kill_text (rl_point, rl_mark);
  507. }
  508.  
  509. rl_vi_change_to (count, key)
  510.      int count, key;
  511. {
  512.   if (uppercase_p (key))
  513.     rl_stuff_char ('$');
  514.  
  515.   if (rl_vi_domove ())
  516.     {
  517.       ding ();
  518.       return;
  519.     }
  520.  
  521.   rl_begin_undo_group ();
  522.   vi_doing_insert = 1;
  523.   rl_kill_text (rl_point, rl_mark);
  524.   rl_vi_insertion_mode ();
  525. }
  526.  
  527. rl_vi_yank_to (count, key)
  528.      int count, key;
  529. {
  530.   int save = rl_point;
  531.  
  532.   if (uppercase_p (key))
  533.     rl_stuff_char ('$');
  534.  
  535.   if (rl_vi_domove ())
  536.     {
  537.       ding ();
  538.       return;
  539.     }
  540.  
  541.   rl_begin_undo_group ();
  542.   rl_kill_text (rl_point, rl_mark);
  543.   rl_end_undo_group ();
  544.   rl_do_undo ();
  545.   rl_point = save;
  546. }
  547.  
  548. rl_vi_delete (count)
  549. {
  550.   if (rl_point >= rl_end - 1)
  551.     {
  552.       rl_delete (count);
  553.       if (rl_point > 0)
  554.     rl_backward (1);
  555.     }
  556.   else
  557.     rl_delete (count);
  558. }
  559.  
  560. /* Turn the current line into a comment in shell history.  A ksh function */
  561. rl_vi_comment ()
  562. {
  563.   rl_beg_of_line ();
  564.   rl_insert_text (": ");    /* # doesn't work in interactive mode */
  565.   rl_redisplay ();
  566.   rl_newline (1, '\010');
  567. }
  568.  
  569. rl_vi_first_print ()
  570. {
  571.   rl_back_to_indent ();
  572. }
  573.  
  574. rl_back_to_indent (ignore1, ignore2)
  575.      int ignore1, ignore2;
  576. {
  577.   rl_beg_of_line ();
  578.   while (rl_point < rl_end && whitespace (the_line[rl_point]))
  579.     rl_point++;
  580. }
  581.  
  582. /* NOTE: it is necessary that opposite directions are inverses */
  583. #define    FTO     1        /* forward to */
  584. #define BTO    -1        /* backward to */
  585. #define FFIND     2        /* forward find */
  586. #define BFIND    -2        /* backward find */
  587.  
  588. rl_vi_char_search (count, key)
  589.      int count, key;
  590. {
  591.   static char target;
  592.   static int orig_dir, dir;
  593.   int pos;
  594.  
  595.   if (key == ';' || key == ',')
  596.     dir = (key == ';' ? orig_dir : -orig_dir);
  597.   else
  598.     {
  599.       target = rl_getc (in_stream);
  600.  
  601.       switch (key)
  602.     {
  603.     case 't':
  604.       orig_dir = dir = FTO;
  605.       break;
  606.  
  607.     case 'T':
  608.       orig_dir = dir = BTO;
  609.       break;
  610.  
  611.     case 'f':
  612.       orig_dir = dir = FFIND;
  613.       break;
  614.  
  615.     case 'F':
  616.       orig_dir = dir = BFIND;
  617.       break;
  618.     }
  619.     }
  620.  
  621.   pos = rl_point;
  622.  
  623.   if (dir < 0)
  624.     {
  625.       pos--;
  626.       do
  627.     {
  628.       if (the_line[pos] == target)
  629.         {
  630.           if (dir == BTO)
  631.         rl_point = pos + 1;
  632.           else
  633.         rl_point = pos;
  634.           return;
  635.         }
  636.     }
  637.       while (pos--);
  638.  
  639.       if (pos < 0)
  640.     {
  641.       ding ();
  642.       return;
  643.     }
  644.     }
  645.   else
  646.     {            /* dir > 0 */
  647.       pos++;
  648.       do
  649.     {
  650.       if (the_line[pos] == target)
  651.         {
  652.           if (dir == FTO)
  653.         rl_point = pos - 1;
  654.           else
  655.         rl_point = pos;
  656.           return;
  657.         }
  658.     }
  659.       while (++pos < rl_end);
  660.  
  661.       if (pos >= (rl_end - 1))
  662.     ding ();
  663.     }
  664. }
  665.  
  666. /* Match brackets */
  667. rl_vi_match ()
  668. {
  669.   int count = 1, brack, pos;
  670.  
  671.   pos = rl_point;
  672.   if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
  673.     {
  674.       while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
  675.          rl_point < rl_end - 1)
  676.     rl_forward (1);
  677.  
  678.       if (brack <= 0)
  679.     {
  680.       rl_point = pos;
  681.       ding ();
  682.       return;
  683.     }
  684.     }
  685.  
  686.   pos = rl_point;
  687.  
  688.   if (brack < 0)
  689.     {
  690.       while (count)
  691.     {
  692.       if (--pos >= 0)
  693.         {
  694.           int b = rl_vi_bracktype (the_line[pos]);
  695.           if (b == -brack)
  696.         count--;
  697.           else if (b == brack)
  698.         count++;
  699.         }
  700.       else
  701.         {
  702.           ding ();
  703.           return;
  704.         }
  705.     }
  706.     }
  707.   else
  708.     {            /* brack > 0 */
  709.       while (count)
  710.     {
  711.       if (++pos < rl_end)
  712.         {
  713.           int b = rl_vi_bracktype (the_line[pos]);
  714.           if (b == -brack)
  715.         count--;
  716.           else if (b == brack)
  717.         count++;
  718.         }
  719.       else
  720.         {
  721.           ding ();
  722.           return;
  723.         }
  724.     }
  725.     }
  726.   rl_point = pos;
  727. }
  728.  
  729. int
  730. rl_vi_bracktype (c)
  731.      int c;
  732. {
  733.   switch (c)
  734.     {
  735.     case '(': return  1;
  736.     case ')': return -1;
  737.     case '[': return  2;
  738.     case ']': return -2;
  739.     case '{': return  3;
  740.     case '}': return -3;
  741.     default:  return  0;
  742.     }
  743. }
  744.  
  745. rl_vi_change_char ()
  746. {
  747.   int c;
  748.  
  749.   c = rl_getc (in_stream);
  750.  
  751.   switch (c)
  752.     {
  753.     case '\033':
  754.     case CTRL('C'):
  755.       return;
  756.  
  757.     default:
  758.       rl_begin_undo_group ();
  759.       rl_delete (1);
  760.       rl_insert (1, c);
  761.       rl_end_undo_group ();
  762.       break;
  763.     }
  764. }
  765.  
  766. rl_vi_subst (count, key)
  767.      int count, key;
  768. {
  769.   rl_begin_undo_group ();
  770.   vi_doing_insert = 1;
  771.  
  772.   if (uppercase_p (key))
  773.     {
  774.       rl_beg_of_line ();
  775.       rl_kill_line (1);
  776.     }
  777.   else
  778.     rl_delete (1);
  779.  
  780.   rl_vi_insertion_mode ();
  781. }
  782.  
  783. rl_vi_overstrike (count, key)
  784.      int count, key;
  785. {
  786.   int i;
  787.  
  788.   if (vi_doing_insert == 0)
  789.     {
  790.       vi_doing_insert = 1;
  791.       rl_begin_undo_group ();
  792.     }
  793.  
  794.   for (i = 0; i < count; i++)
  795.     {
  796.       vi_replace_count++;
  797.       rl_begin_undo_group ();
  798.  
  799.       if (rl_point < rl_end)
  800.     {
  801.       rl_delete (1);
  802.       rl_insert (1, key);
  803.     }
  804.       else
  805.     rl_insert (1, key);
  806.  
  807.       rl_end_undo_group ();
  808.     }
  809. }
  810.  
  811. rl_vi_overstrike_delete (count)
  812.      int count;
  813. {
  814.   int i, s;
  815.  
  816.   for (i = 0; i < count; i++)
  817.     {
  818.       if (vi_replace_count == 0)
  819.     {
  820.       ding ();
  821.       break;
  822.     }
  823.       s = rl_point;
  824.  
  825.       if (rl_do_undo ())
  826.     vi_replace_count--;
  827.  
  828.       if (rl_point == s)
  829.     rl_backward (1);
  830.     }
  831.  
  832.   if (vi_replace_count == 0 && vi_doing_insert)
  833.     {
  834.       rl_end_undo_group ();
  835.       rl_do_undo ();
  836.       vi_doing_insert = 0;
  837.     }
  838. }
  839.  
  840. rl_vi_replace ()
  841. {
  842.   int i;
  843.  
  844.   vi_replace_count = 0;
  845.  
  846.   vi_replace_map = rl_make_bare_keymap ();
  847.  
  848.   for (i = ' '; i < 127; i++)
  849.     vi_replace_map[i].function = rl_vi_overstrike;
  850.  
  851.   vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
  852.   vi_replace_map[ESC].function = rl_vi_movement_mode;
  853.   vi_replace_map[RETURN].function = rl_newline;
  854.   vi_replace_map[NEWLINE].function = rl_newline;
  855.   keymap = vi_replace_map;
  856. }
  857.